﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Documents
Imports System.Windows.Media

''' <summary>
''' A UI adorner that renders connectors between nodes in a graph.
''' </summary>
Public Class NodeConnectionAdorner
    Inherits Adorner

#Region "Constructor"

    Public Sub New(ByVal adornedElement As UIElement)
        MyBase.New(adornedElement)
        _nodeConnectors = New List(Of NodeConnector)
    End Sub

#End Region

#Region "Properties"

    Public Property Graph() As Graph
        Get
            Return _graph
        End Get
        Set(ByVal value As Graph)
            If value.Equals(_graph) Then
                Return
            End If

            _graph = value

            If Not _graph Is Nothing Then
                Me.ProcessGraph()
            End If
        End Set
    End Property

#End Region

#Region "Private Helpers"

    Sub ProcessGraph()
        Me.RemoveConnectors()

        For Each node As Node In _graph.Nodes
            For Each dependency As Node In node.NodeDependencies
                Me.AddConnector(node, dependency)
            Next
        Next

        MyBase.InvalidateMeasure()
    End Sub

    Sub RemoveConnectors()
        For Each connector As NodeConnector In _nodeConnectors
            MyBase.RemoveVisualChild(connector)
            MyBase.RemoveLogicalChild(connector)
        Next

        _nodeConnectors.Clear()
    End Sub

    Sub AddConnector(ByVal startNode As Node, ByVal endNode As Node)
        Dim connector As NodeConnector = New NodeConnector(startNode, endNode)

        _nodeConnectors.Add(connector)

        ' Add the connector to the visual and logical tree so that
        ' rendering and resource inheritance will work properly.
        Me.AddVisualChild(connector)
        Me.AddLogicalChild(connector)
    End Sub

#End Region

#Region "Base Class Overrides"

    Protected Overloads Overrides ReadOnly Property LogicalChildren() As IEnumerator
        Get
            Return _nodeConnectors.GetEnumerator()
        End Get
    End Property

    Protected Overloads Overrides ReadOnly Property VisualChildrenCount() As Integer
        Get
            Return _nodeConnectors.Count
        End Get
    End Property

    Protected Overloads Overrides Function GetVisualChild(ByVal index As Integer) As Visual
        Return _nodeConnectors(index)
    End Function

    Protected Overloads Overrides Function MeasureOverride(ByVal constraint As Size) As Size
        For Each nodeConnector As NodeConnector In _nodeConnectors
            nodeConnector.Measure(constraint)
        Next

        If [Double].IsInfinity(constraint.Width) OrElse [Double].IsInfinity(constraint.Height) Then
            Return New Size(10000, 10000)
        End If

        Return constraint
    End Function

    Protected Overloads Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
        Dim bounds As System.Windows.Rect = VisualTreeHelper.GetDescendantBounds(MyBase.AdornedElement)

        If Not bounds.IsEmpty Then
            For Each nodeConnector In _nodeConnectors
                nodeConnector.Arrange(bounds)
            Next
        End If

        Return finalSize
    End Function

#End Region

#Region "Fields"

    ReadOnly _nodeConnectors As List(Of NodeConnector)
    Private _graph As Graph

#End Region

End Class